package com.github.baichuan.application.scaffold.security;

import com.github.baichuan.web.dto.Result;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;

/**
 * 密码暴力破解防护
 */
public class BruteForceAttackProtection {
    /**
     * 密码最大失败次数
     */
    private int maxFails;

    /**
     * 密码错误锁定时长(分钟)
     */
    private int lockMinutes;

    /**
     * 账号失败次数
     */
    private Cache<String, Integer> failCounts = null;

    public BruteForceAttackProtection(int maxFails, int lockMinutes){
        this.maxFails = maxFails;
        this.lockMinutes = lockMinutes;

        if(maxFails > 0 && lockMinutes > 0){
            this.failCounts = Caffeine.newBuilder()
                    .expireAfterAccess(lockMinutes, TimeUnit.MINUTES)
                    .build();
        }
    }

    /**
     * 检测是否锁定
     */
    public Result detect(String loginName){
        Integer count = getFailCount(loginName);

        if(count > 0 && count >= maxFails) {
            return Result.fail("账号已被锁定，请等待" + lockMinutes + "分钟以后重试");
        }

        return Result.success("");
    }

    /**
     * 登录成功
     */
    public Result success(String loginName){
        if(failCounts != null){
            failCounts.invalidate(loginName);
        }

        return Result.success("");
    }

    /**
     * 登录失败
     * @return
     */
    public Result failure(String loginName){
        if(failCounts == null){
            return Result.fail("用户名或密码错误");
        }

        Integer count = getFailCount(loginName);
        count = count + 1;
        failCounts.put(loginName, count);
        return Result.fail("密码错误" + maxFails + "次以后账号将被锁定，剩余" + (maxFails - count) + "次");
    }

    /**
     * 获取失败次数
     */
    private int getFailCount(String loginName){
        if(failCounts == null){
            return 0;
        }

        Integer count = failCounts.getIfPresent(loginName);
        if(count == null) {
            count = 0;
        }
        return count;
    }
}
